package handling.login;

import client.MapleClient;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class AccountStorage {
    private ReentrantReadWriteLock mutex;
    private Lock readLock;
    private Lock writeLock;
    private Map<Integer, MapleClient> idToClient;

    public AccountStorage() {
        this.mutex = new ReentrantReadWriteLock();
        this.readLock = this.mutex.readLock();
        this.writeLock = this.mutex.writeLock();
        this.idToClient = (Map<Integer, MapleClient>) new HashMap();
    }

    public Collection<MapleClient> getAllClients() {
        this.readLock.lock();
        try {
            return Collections.unmodifiableCollection(this.idToClient.values());
        }
        finally {
            this.readLock.unlock();
        }
    }

    public List<MapleClient> getAllClientsThreadSafe() {
        List<MapleClient> ret = (List<MapleClient>) new ArrayList();
        ret.addAll(this.getAllClients());
        return ret;
    }

    public void registerAccount(MapleClient c) {
        this.writeLock.lock();
        try {
            this.idToClient.put(Integer.valueOf(c.getAccID()), c);
        }
        finally {
            this.writeLock.unlock();
        }
    }

    public void deregisterAccount(MapleClient c) {
        this.writeLock.lock();
        try {
            List<Integer> clients = (List<Integer>) new ArrayList();
            for (Entry<Integer, MapleClient> entry : this.idToClient.entrySet()) {
                if (entry.getValue() == c) {
                    clients.add(entry.getKey());
                }
            }
            Iterator<Integer> iterator2 = clients.iterator();
            while (iterator2.hasNext()) {
                int id = ((Integer) iterator2.next()).intValue();
                this.idToClient.remove(Integer.valueOf(id));
            }
        }
        finally {
            this.writeLock.unlock();
        }
    }

    public void deregisterAccountById(int id) {
        this.writeLock.lock();
        try {
            this.idToClient.remove(Integer.valueOf(id));
        }
        finally {
            this.writeLock.unlock();
        }
    }

    public int pendingClientSize(int world) {
        Map<Integer, MapleClient> clients = (Map<Integer, MapleClient>) new HashMap();
        for (MapleClient c : this.idToClient.values()) {
            if (c.getWorld() == world) {
                clients.put(Integer.valueOf(c.getAccID()), c);
            }
        }
        return clients.size();
    }

    public MapleClient getClientByName(String name) {
        MapleClient client = null;
        this.readLock.lock();
        try {
            for (MapleClient c : this.idToClient.values()) {
                if (c.getAccountName().equalsIgnoreCase(name)) {
                    client = c;
                }
            }
        }
        finally {
            this.readLock.unlock();
        }
        return client;
    }

    public MapleClient getCharacterById(int id) {
        this.readLock.lock();
        try {
            return (MapleClient) this.idToClient.get(Integer.valueOf(id));
        }
        finally {
            this.readLock.unlock();
        }
    }

    public int getConnectedClients() {
        return this.idToClient.size();
    }

    public void disconnectAll() {
        this.disconnectAll(false);
    }

    public void disconnectAll(boolean checkGM) {
        this.writeLock.lock();
        try {
            Iterator<MapleClient> itr = this.idToClient.values().iterator();
            while (itr.hasNext()) {
                MapleClient c = (MapleClient) itr.next();
                if (!c.isGm() || !checkGM) {
                    c.disconnect(false, false, true);
                    c.getSession().close();
                    itr.remove();
                }
            }
        }
        finally {
            this.writeLock.unlock();
        }
    }

    public void disconnectAll(MapleClient cl) {
        this.writeLock.lock();
        try {
            Iterator<MapleClient> itr = this.idToClient.values().iterator();
            while (itr.hasNext()) {
                MapleClient c = (MapleClient) itr.next();
                if (c.getGmLevel() < cl.getGmLevel()) {
                    c.disconnect(false, false, true);
                    c.getSession().close();
                    itr.remove();
                }
            }
        }
        finally {
            this.writeLock.unlock();
        }
    }

    public String getOnlinePlayers(boolean byGM) {
        StringBuilder sb = new StringBuilder();
        if (byGM) {
            this.readLock.lock();
            try {
                Iterator<MapleClient> itr = this.idToClient.values().iterator();
                while (itr.hasNext()) {
                    sb.append(((MapleClient) itr.next()).getAccountName());
                    sb.append(", ");
                }
            }
            finally {
                this.readLock.unlock();
            }
        } else {
            this.readLock.lock();
            try {
                for (MapleClient c : this.idToClient.values()) {
                    if (!c.isGm()) {
                        sb.append(c.getAccountName());
                        sb.append(", ");
                    }
                }
            }
            finally {
                this.readLock.unlock();
            }
        }
        return sb.toString();
    }

    public void broadcastPacket(byte[] data) {
        this.readLock.lock();
        try {
            Iterator<MapleClient> itr = this.idToClient.values().iterator();
            while (itr.hasNext()) {
                ((MapleClient) itr.next()).sendPacket(data);
            }
        }
        finally {
            this.readLock.unlock();
        }
    }

    public void broadcastGMPacket(byte[] data) {
        this.readLock.lock();
        try {
            for (MapleClient c : this.idToClient.values()) {
                if (c.isLoggedIn() && c.isGm()) {
                    c.sendPacket(data);
                }
            }
        }
        finally {
            this.readLock.unlock();
        }
    }
}
